mod utils;
mod service;
use core::str;
use std::{collections::BTreeMap, fs::{self, File}, io::{Error, ErrorKind, Write}, path::Path};

use directories::BaseDirs;
use idgen::IDGen;
use lopdf::{Dictionary, Document, Object, Stream};
use rand::Rng;
use serde::{Deserialize, Serialize};
use utils::{file_utils::{self, creat_dir, get_tree, Tree}, git_utils};

extern crate file;

// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}! You've been greeted from Rust!", name)
}

#[tauri::command]
fn upload_file(fromFile: String, toPath: String) {
  let fileName = rand::thread_rng().sample_iter(&rand::distributions::Alphanumeric).take(10).map(char::from).collect::<String>();
  let _ = fs::create_dir_all(toPath.clone() + "\\img\\");
  match fs::copy(fromFile, toPath + "\\img\\" + &fileName) {
    Ok(_) => {println!("保存成功！")},
    Err(e) => {println!("保存失败！{}", e)},
  }
}


#[tauri::command]
fn write_file(path: String, fileName: String, data: String) {
  println!("{}", path);
  println!("{}", fileName);

  match std::fs::File::create(path.clone() + "/" + &fileName).map(std::io::BufWriter::new) {
    Ok(_) => {
        
        file::put_text(path + "/" + &fileName, data.clone()).ok();
    },
    Err(_) => {
        let _ = std::fs::create_dir_all(&path);
        match std::fs::File::create(path.clone() + "/" + &fileName).map(std::io::BufWriter::new) {
            Ok(_) => {
        
                file::put_text(path + "/" + &fileName, data.clone()).ok();
            },
            Err(_) => {
                println!("生成文件失败！")
            }
        }
    }
  }
}


#[tauri::command]
fn read_file(path: String) -> String {
  println!("{}", path);
  match file::get_text(path) {
    Ok(text) => {
      return text;
    },
    Err(e) => {
      println!("获取数据失败！{}", e);
      return format!("#@#error#@#_{}", e);
    },
  }
}


#[tauri::command]
fn save_file(content: String, path: String) -> String {
  file_utils::save_file(content, path);
  let idgen = IDGen::new(1);
  let id = idgen.new_id();
  id.to_string()
}


#[tauri::command]
fn del_file(path: String) {
  match fs::remove_file(path) {
    Ok(_) => println!("删除成功!"),
    Err(_) => println!("删除失败!"),
  }
}


#[tauri::command]
fn init_repository(url: String, path: String) {
  creat_dir(path.clone());
  //创建仓库
  git_utils::init(&url, &path);
}

#[tauri::command]
fn pull(url: String, path: String) {
  let remote_name = "origin";
  let remote_branch = "master";
  creat_dir(path.clone());
  git_utils::pull(&url, &path, remote_name, remote_branch);
}

#[tauri::command]
fn push_all(url: String, path: String, username: String, email: String, login_name: String, password: String) {
  git_utils::push_all(&url, &path, username, email, login_name, password);
}

#[tauri::command]
fn push(url: String, path: String, file_path: String, username: String, email: String, login_name: String, password: String) {
  git_utils::push(&url, &path, &file_path.replace(&path, ""), username, email, login_name, password);
}

#[tauri::command]
fn push_del_file(url: String, path: String, file_path: String, username: String, email: String, login_name: String, password: String) {
  git_utils::del_file(&url, &path, &file_path.replace(&path, ""), username, email, login_name, password);
}



#[tauri::command]
fn get_list_file(path: String) -> Vec<Tree> {
  get_tree(path)
}




#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
  tauri::Builder::default()
      .plugin(tauri_plugin_fs::init())
      .plugin(tauri_plugin_dialog::init())
      .plugin(tauri_plugin_shell::init())
      .invoke_handler(tauri::generate_handler![greet, upload_file, write_file, read_file, get_list_file, save_file, del_file, init_repository, pull, push_all, push, push_del_file])
      .run(tauri::generate_context!())
      .expect("error while running tauri application");
  println!("初始化成功2");



  let mut path = String::from("");
  if let Some(base_dirs) = BaseDirs::new() {
      let appdata_dir = base_dirs.data_dir();
      path += appdata_dir.to_str().unwrap();
      println!("AppData directory: {:?}", appdata_dir);
  }
  path += "\\tk.rmk";
  
  creat_dir(path);
}


#[test]
fn test() {

 // 加载 PDF 文档
 let mut doc = Document::load("C:\\Users\\tjw1t\\Downloads\\321.pdf").expect("Failed to load PDF");

 // 获取所有页面
 let pages: BTreeMap<u32, (u32, u16)> = doc.get_pages();

 for (page_id, p) in pages {
     // 获取页面内容
     let content = doc.get_page_content(p).expect("Failed to decode page content");

                  // 将内容转换为字符串，查找并替换目标词语
                  let mut content_str = str::from_utf8(&content).expect("Failed to convert page content to string").to_string();



                  if content_str.contains("场景") {
                      content_str = content_str.replace("场景", "**");
                      println!("Replaced '{}' with '{}' on page {}", "场景", "**", page_id);
                  }
                  
                  let dd = doc.new_object_id();
          
                  match doc.get_dictionary(p) {
                      Ok(dict) => {
                                // 将修改后的内容重新编码为字节流
                                let modified_content = Stream::new(dict.clone(), content_str.into_bytes());
          
                                // 更新页面内容
                                doc.objects.insert(dd, Object::Stream(modified_content));
                      },
                      Err(_) => {
                        println!("");
                      },
                  }


 }

 // 保存修改后的 PDF 文件
 doc.save("C:\\Users\\tjw1t\\Downloads\\333.pdf").expect("Failed to save modified PDF");

 //println!("PDF modified and saved to {}", output_file);


  //pdf2text("C:\\Users\\tjw1t\\Downloads\\321.pdf", "C:\\Users\\tjw1t\\Downloads\\333.text", false, "");
}












fn extract_fonts_from_page(doc: &Document, page_id: (u32, u16)) -> BTreeMap<String, Dictionary> {
  let mut fonts = BTreeMap::new();

  match doc.get_page_fonts(page_id) {
    Ok(page) => {
      if let Some(resource_dict) = page.get(b"Resources".trim_ascii()) {

            if let Ok(font_dict) = resource_dict.get(b"Font") {
                if let Ok(fonts_dict) = font_dict.as_dict() {
                    for (font_name, font_obj_ref) in fonts_dict.iter() {
                        if let Ok(font_obj) = doc.get_object(font_obj_ref.as_reference().unwrap()) {
                            if let Ok(font) = font_obj.as_dict() {
                                fonts.insert(font_name.clone(), font.clone());
                            }
                        }
                    }
                }
            }
        
    }
    },
    Err(_) => todo!(),
  }

  fonts
}

fn extract_to_unicode_map(doc: &Document, font: &Dictionary) -> Option<BTreeMap<String, String>> {
  match font.get(b"ToUnicode") {
    Ok(to_unicode) => {
      if let Ok(to_unicode_ref) = to_unicode.as_reference() {
        if let Ok(stream_obj) = doc.get_object(to_unicode_ref) {
            if let Ok(stream) = stream_obj.as_stream() {
                let decoded = stream.decode_content().unwrap();
                match decoded.encode() {
                    Ok(dd) => {
                      let content = String::from_utf8_lossy(&dd);
                      return Some(parse_to_unicode_map(&content));
                    },
                    Err(_) => {
                      return None;
                    },
                }
               
            }
            return None;
        }
        return None;
      }
      return None;
    },
    Err(_) => None,
  }
  
}

// 解析 ToUnicode CMap 映射
fn parse_to_unicode_map(cmap_content: &str) -> BTreeMap<String, String> {
  let mut map = BTreeMap::new();
  let mut lines = cmap_content.lines();

  while let Some(line) = lines.next() {
      if line.starts_with("<") && line.contains("beginbfchar") {
          while let Some(char_map_line) = lines.next() {
              if char_map_line.starts_with("<") {
                  let parts: Vec<&str> = char_map_line.split_whitespace().collect();
                  if parts.len() == 2 {
                      let encoded_char = parts[0].trim_matches('<').trim_matches('>');
                      let decoded_char = parts[1].trim_matches('<').trim_matches('>');
                      map.insert(encoded_char.to_string(), decode_unicode(decoded_char));
                  }
              }
              if char_map_line.contains("endbfchar") {
                  break;
              }
          }
      }
  }

  map
}


// 解码 Unicode 字符
fn decode_unicode(hex: &str) -> String {
  let code = u32::from_str_radix(hex, 16).unwrap();
  char::from_u32(code).unwrap().to_string()
}